/*
 * @Author: Laputa
 * @Version: V0.1
 * @Date: 2023-07-11 16:29:51
 * @LastEditors: Laputa
 * @LastEditTime: 2023-10-13 15:02:16
 * @Description:This file provides firmware functions to manage the following
 *              functionalities of the DMA part.
 *
 *              DMA Control
 *              DMA TCD Configuration
 *              DMA Channel Priority
 *              DMA Channel Hardware Request
 *              DMA Channel Error Interrupt Operation
 *              DMA Channel Interrupt Operation
 *              DMA Channel Status Operation
 *
 * Copyright (c) 2023 by Levetop, All Rights Reserved.
 */

#include "lt168_dma.h"

/*******************************************************************************
 * Code
 ******************************************************************************/

/**
 * @brief  Sets default values for the dma control configuration structure variable pointer.
 * @param  {dma_control_config_ts *} config: Pointer to a dma control configuration structure.
 * @return {void}
 */
void DMA_Control_Reset(dma_control_config_ts *config)
{
    config->debug = 0U;
    config->round_robin_channel_arbitration = 0U;
    config->round_robin_group_arbitration = 0U;
    config->halt_on_error = 1U; /* halt dma transfer when happen error */
    config->halt_dma = 0U;
    config->minor_continuous_link = 0U;
    config->minor_loop_mapping = 0U;
}

/**
 * @brief  Sets default values for the dma tcd configuration structure variable pointer.
 * @param  {dma_tcd_config_ts *} config: Pointer to a dma tcd configuration structure.
 * @return {void}
 */
void DMA_TCD_Reset(dma_tcd_config_ts * tcd_config)
{
    tcd_config->source = 0U;
    tcd_config->source_datasize = 0U;
    tcd_config->source_offset = 0U;
    tcd_config->source_modulo = 0U;
    tcd_config->source_mloe = 0U;
    tcd_config->source_last_address_adjustment = 0U;

    tcd_config->destin = 0U;
    tcd_config->destin_datasize = 0U;
    tcd_config->destin_offset = 0U;
    tcd_config->destin_modulo = 0U;
    tcd_config->destin_mloe = 0U;
    tcd_config->destin_last_address_adjustment = 0U;

    tcd_config->minor_loop_offset = 0U;
    tcd_config->minor_transfer_num = 0U;
    tcd_config->major_loop_num = 0U;
    
    tcd_config->minor_link = 0U;
    tcd_config->minor_link_channel = 0U;
    tcd_config->major_link = 0U;
    tcd_config->major_link_channel = 0U;

    tcd_config->e_sg_tcd_point = 0U;

    tcd_config->bwc = 0U;
    tcd_config->e_sg = 0U;
    tcd_config->d_req = 0U;
    tcd_config->interrupt_half = 0U;
    tcd_config->interrupt_major = 0U;
}

/**
 * @brief  Initializes the DMA peripheral according to the specified parameters in the config.
 * @param  {dma_control_config_ts *} config: Pointer to a dma_control_config_ts structure.
 * @return {void}
 */
void DMA_Control_Init(dma_control_config_ts *config)
{
    uint32_t tempReg = 0U;
    tempReg |= DMA_CR_EDBG(config->debug) |
              DMA_CR_ERCA(config->round_robin_channel_arbitration) |
              DMA_CR_ERGA(config->round_robin_group_arbitration) |
              DMA_CR_HOE (config->halt_on_error) |
              DMA_CR_HALT(config->halt_dma) |
              DMA_CR_CLM (config->minor_continuous_link) |
              DMA_CR_EMLM(config->minor_loop_mapping);
    DMA->CR = tempReg;
}

/**
 * @brief  Initializes the TCD according to the specified parameters in the tcd_config.
 * @param  {dma_tcd *} tcd: Pointer to a dma channel transfer control descriptor structure
 *         where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15 or other transfer control 
 *         descriptor structure in ram.
 * @param  {dma_tcd_config_ts *} tcd_config: Pointer to a dma tcd configuration structure.
 * @return {ResultStatus} Return value can be OK,ERROR.
 */

//ResultStatus DMA_TCD_Init(dma_tcd * tcd, dma_tcd_config_ts * tcd_config)
//{
//    uint32_t tempValue = (uint32_t)tcd;
//    if ((tempValue & 0xF0000000U) == 0x40000000U) /* tcd_config is point to TCD Hardware register */
//    {
//        uint16_t tmp_cs = tcd->CONTROL_STATUS;
//        if(Bit_Read(tmp_cs,DMA_TCD_CONTROL_STATUS_ACTIVE_MARK) == DMA_TCD_CONTROL_STATUS_ACTIVE_MARK ||\
//           tcd->BITER_LINK_OFF != tcd->CITER_LINK_OFF
//        )
//        {
//            return ERROR; /* channel acitve and CITER unequal to BITER  can't configuration TCD register. */
//        }
//    }
//    uint32_t tempReg = 0U;
//
//    /* Minor Loop */
//    // Source part
//    tcd->SADDR = tcd_config->source;
//    tcd->SOFF = tcd_config->source_offset;
//    tcd->SLAST = tcd_config->source_last_address_adjustment;
//
//    tcd->DADDR = tcd_config->destin;
//    tcd->DOFF = tcd_config->destin_offset;
//    tcd->DLAST_SGA = tcd_config->destin_last_address_adjustment;
//
//    tempReg |= DMA_TCD_TA_SSIZE(tcd_config->source_datasize) |
//              DMA_TCD_TA_SMOD(tcd_config->source_modulo)    |
//              DMA_TCD_TA_DSIZE(tcd_config->destin_datasize) |
//              DMA_TCD_TA_DMOD(tcd_config->destin_modulo) ;
//
//    tcd->TA = tempReg;
//    if (Bit_Read(DMA->CR, DMA_CR_EMLM_MASK) == DMA_CR_EMLM_MASK && \
//        tcd_config->source_mloe == Disable && \
//        tcd_config->destin_mloe == Disable)
//    {
//        tcd->NBYTES_MLOFF_30bit = DMA_TCD_NBYTES_30bit(tcd_config->minor_transfer_num);
//    }
//    else if (Bit_Read(DMA->CR, DMA_CR_EMLM_MASK) == DMA_CR_EMLM_MASK)
//    {
//        tempReg = 0U;
//        tempReg |= DMA_TCD_NBYTES_10bit_SMLOE(tcd_config->source_mloe) |
//                  DMA_TCD_NBYTES_10bit_DMLOE(tcd_config->destin_mloe) |
//                  DMA_TCD_NBYTES_10bit_MLOFF(tcd_config->minor_loop_offset) |
//                  DMA_TCD_NBYTES_10bit(tcd_config->minor_transfer_num);
//
//        tcd->NBYTES_MLOFF_10bit = tempReg;
//    }
//    else
//    {
//        tcd->NBYTES_32bit = tcd_config->minor_transfer_num;
//    }
//
//    if (tcd_config->minor_link == Enable)
//    {
//        tempReg = 0U;
//        tempReg |= DMA_TCD_CITER_LINK_ON_ELINK(Enable) |
//                  DMA_TCD_CITER_LINK_ON_LINKCH(tcd_config->minor_link_channel) |
//                  DMA_TCD_CITER_LINK_ON_CITER(tcd_config->major_loop_num);
//
//        tcd->CITER_LINK_ON = tempReg;
//        tcd->BITER_LINK_ON = tempReg;
//    }
//    else
//    {
//        tempReg = 0U;
//        tempReg = DMA_TCD_CITER_LINK_OFF_CITER(tcd_config->major_loop_num);
//        tcd->CITER_LINK_OFF = tempReg;
//        tcd->BITER_LINK_OFF = tempReg;
//    }
//
//    /* Major Loop */
//    tempReg = 0U;
//    if (tcd_config->major_link == Enable)
//    {
//        tempReg |= DMA_TCD_CONTROL_STATUS_MAJORLINK(Enable) |
//                  DMA_TCD_CONTROL_STATUS_LINKCH(tcd_config->major_link_channel);
//    }
//
//    tempReg |= DMA_TCD_CONTROL_STATUS_BWC(tcd_config->bwc) |
//              DMA_TCD_CONTROL_STATUS_ESG(tcd_config->e_sg)|
//              DMA_TCD_CONTROL_STATUS_DREQ(tcd_config->d_req) |
//              DMA_TCD_CONTROL_STATUS_INTHALF(tcd_config->interrupt_half) |
//              DMA_TCD_CONTROL_STATUS_INTMAJ(tcd_config->interrupt_major);
//
//    tcd->CONTROL_STATUS = tempReg;
//
//    /* Scatter-Gather */
//    if(tcd_config->e_sg == Enable)
//        tcd->DLAST_SGA = tcd_config->e_sg_tcd_point;
//
//    return OK;
//}
//QSPI_Vincent
ResultStatus DMA_TCD_Init(dma_tcd * tcd, dma_tcd_config_ts * tcd_config)
{
    uint32_t tempValue = (uint32_t)tcd;
    if ((tempValue & 0xF0000000U) == 0x40000000U) /* tcd_config is point to TCD Hardware register */
    {
        uint16_t tmp_cs = tcd->CONTROL_STATUS;
        if((Bit_Read(tmp_cs,DMA_TCD_CONTROL_STATUS_ACTIVE_MARK) == DMA_TCD_CONTROL_STATUS_ACTIVE_MARK) ||\
           (tcd->BITER_LINK_OFF != tcd->CITER_LINK_OFF)
        )
        {
            return ERROR; /* channel acitve and CITER unequal to BITER  can't configuration TCD register. */
        }
    }
    uint32_t tempReg = 0U;

    /* Minor Loop */
    // Source part
    tcd->SADDR = tcd_config->source;
    if(tcd->SADDR != tcd_config->source)
    	return ERROR;

    tcd->SOFF = tcd_config->source_offset;
    if(tcd->SOFF != tcd_config->source_offset)
    	return ERROR;

    tcd->SLAST = tcd_config->source_last_address_adjustment;
    if(tcd->SLAST != tcd_config->source_last_address_adjustment)
    	return ERROR;

    tcd->DADDR = tcd_config->destin;
    if(tcd->DADDR != tcd_config->destin)
    	return ERROR;

    tcd->DOFF = tcd_config->destin_offset;
    if(tcd->DOFF != tcd_config->destin_offset)
    	return ERROR;

    tcd->DLAST_SGA = tcd_config->destin_last_address_adjustment;
    if(tcd->DLAST_SGA != tcd_config->destin_last_address_adjustment)
    	return ERROR;

    tempReg |= DMA_TCD_TA_SSIZE(tcd_config->source_datasize) |
              DMA_TCD_TA_SMOD(tcd_config->source_modulo)    |
              DMA_TCD_TA_DSIZE(tcd_config->destin_datasize) |
              DMA_TCD_TA_DMOD(tcd_config->destin_modulo) ;

    tcd->TA = (tempReg & 0xFFFFU);

    if(tcd->TA != (tempReg & 0xFFFFU))
    	return ERROR;

    if (Bit_Read(DMA->CR, DMA_CR_EMLM_MASK) == DMA_CR_EMLM_MASK && \
        tcd_config->source_mloe == Disable && \
        tcd_config->destin_mloe == Disable)
    {
        tcd->NBYTES_MLOFF_30bit = DMA_TCD_NBYTES_30bit(tcd_config->minor_transfer_num);

        if(tcd->NBYTES_MLOFF_30bit != DMA_TCD_NBYTES_30bit(tcd_config->minor_transfer_num))
        	return ERROR;
    }
    else if (Bit_Read(DMA->CR, DMA_CR_EMLM_MASK) == DMA_CR_EMLM_MASK)
    {
        tempReg = 0U;
        tempReg |= DMA_TCD_NBYTES_10bit_SMLOE(tcd_config->source_mloe) |
                  DMA_TCD_NBYTES_10bit_DMLOE(tcd_config->destin_mloe) |
                  DMA_TCD_NBYTES_10bit_MLOFF(tcd_config->minor_loop_offset) |
                  DMA_TCD_NBYTES_10bit(tcd_config->minor_transfer_num);

        tcd->NBYTES_MLOFF_10bit = tempReg;

        if(tcd->NBYTES_MLOFF_10bit != tempReg)
        	return ERROR;
    }
    else
    {
        tcd->NBYTES_32bit = tcd_config->minor_transfer_num;

        if(tcd->NBYTES_32bit != tcd_config->minor_transfer_num)
        	return ERROR;
    }

    if (tcd_config->minor_link == Enable)
    {
        tempReg = 0U;
        tempReg |= DMA_TCD_CITER_LINK_ON_ELINK(Enable) |
                  DMA_TCD_CITER_LINK_ON_LINKCH(tcd_config->minor_link_channel) |
                  DMA_TCD_CITER_LINK_ON_CITER(tcd_config->major_loop_num);

        tcd->CITER_LINK_ON = (tempReg & 0xFFFFU);
        tcd->BITER_LINK_ON = (tempReg & 0xFFFFU);

        if(tcd->CITER_LINK_ON != (tempReg & 0xFFFFU) || tcd->BITER_LINK_ON != (tempReg & 0xFFFFU))
        	return ERROR;

        if(tcd->CITER_LINK_ON != tcd->BITER_LINK_ON )
        	return ERROR;
    }
    else
    {
        tempReg = 0U;
        tempReg = DMA_TCD_CITER_LINK_OFF_CITER(tcd_config->major_loop_num);

        tcd->CITER_LINK_OFF = (tempReg & 0xFFFFU);
        tcd->BITER_LINK_OFF = (tempReg & 0xFFFFU);

        if(tcd->CITER_LINK_OFF != (tempReg & 0xFFFFU) || tcd->BITER_LINK_OFF != (tempReg & 0xFFFFU))
        	return ERROR;

        if(tcd->CITER_LINK_OFF != tcd->BITER_LINK_OFF )
        	return ERROR;
    }

    /* Major Loop */
    tempReg = 0U;
    tcd->CONTROL_STATUS = 0;
    if (tcd_config->major_link == Enable)
    {
        tempReg |= DMA_TCD_CONTROL_STATUS_MAJORLINK(Enable) |
                  DMA_TCD_CONTROL_STATUS_LINKCH(tcd_config->major_link_channel);
    }

    tempReg |= DMA_TCD_CONTROL_STATUS_BWC(tcd_config->bwc) |
              DMA_TCD_CONTROL_STATUS_ESG(tcd_config->e_sg)|
              DMA_TCD_CONTROL_STATUS_DREQ(tcd_config->d_req) |
              DMA_TCD_CONTROL_STATUS_INTHALF(tcd_config->interrupt_half) |
              DMA_TCD_CONTROL_STATUS_INTMAJ(tcd_config->interrupt_major);

    tcd->CONTROL_STATUS = (tempReg & 0xFFFFU);

    if(tcd->CONTROL_STATUS != (tempReg & 0xFFFFU))
    	return ERROR;

    /* Scatter-Gather */
    if(tcd_config->e_sg == Enable)
    {
        tcd->DLAST_SGA = tcd_config->e_sg_tcd_point;

        if(tcd->DLAST_SGA != tcd_config->e_sg_tcd_point)
        	return ERROR;
    }
    return OK;
}

//QSPI_Vincent
void DMA_Init(dma_tcd * tcd, dma_tcd_config_ts * tcd_config)
{
	uint8_t time = 0;
	uint8_t dma_res = DMA_TCD_Init(tcd,tcd_config);
	while(dma_res)
	{
		dma_res = DMA_TCD_Init(tcd,tcd_config);
		time++;
		if(time == 4)
		{
			tcd->CONTROL_STATUS = 0;
			tcd->CITER_LINK_OFF = 0;
			tcd->BITER_LINK_OFF = 0;
		}
		if(time > 10)
		{
//			LTPrintf("DMA Configuration Error\r\n");
			while(1);
		}
	}
}

/**
 * @brief Configuration DMA Channel Priority.
 * @param {dma_channel_priority_ts *} pri:Pointer to a dma channel priority
 *               structure that contains the each channel priority configuration parameter.
 * @return {ResultStatus} Return value can be OK,ERROR.
 * @note The software must ensure that the channel priorities contain
 *       unique values!!! Advised to configure all channels at once.
 */
ResultStatus DMA_Configuration_Channel_Priority(dma_channel_priority_ts *pri)
{
    uint8_t temp = 0U;
    uint8_t H_CH = 0U;
    uint8_t L_CH = 0U;
    /* Check whether the channel priority parameter is unique */
    for (uint8_t i = 0U; i < 8U; i++)
    {
        H_CH = (((uint8_t *)pri)[i] & 0xF0U) >> 4U;
        L_CH = (((uint8_t *)pri)[i] & 0x0FU);

        temp += H_CH + L_CH;
    }

    if (temp != 120U)
        return ERROR;

    /* Configuration */
    DMA->CPR0 = DMA_CPR_CHPRI(pri->ch0);
    DMA->CPR1 = DMA_CPR_CHPRI(pri->ch1);
    DMA->CPR2 = DMA_CPR_CHPRI(pri->ch2);
    DMA->CPR3 = DMA_CPR_CHPRI(pri->ch3);
    DMA->CPR4 = DMA_CPR_CHPRI(pri->ch4);
    DMA->CPR5 = DMA_CPR_CHPRI(pri->ch5);
    DMA->CPR6 = DMA_CPR_CHPRI(pri->ch6);
    DMA->CPR7 = DMA_CPR_CHPRI(pri->ch7);
    DMA->CPR8 = DMA_CPR_CHPRI(pri->ch8);
    DMA->CPR9 = DMA_CPR_CHPRI(pri->ch9);
    DMA->CPR10 = DMA_CPR_CHPRI(pri->ch10);
    DMA->CPR11 = DMA_CPR_CHPRI(pri->ch11);
    DMA->CPR12 = DMA_CPR_CHPRI(pri->ch12);
    DMA->CPR13 = DMA_CPR_CHPRI(pri->ch13);
    DMA->CPR14 = DMA_CPR_CHPRI(pri->ch14);
    DMA->CPR15 = DMA_CPR_CHPRI(pri->ch15);

    return OK;
}

/**
 * @brief Configuration DMA Channel Preemption.
 * @param {dma_tcd* } ch: Pointer to a dma channel transfer control descriptor
 *         structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @param {dma_ch_preemption_te} ecp:DMA channel preemption enumeration, 
 *        where can be DMA_ch_cannot_be_suspended,DMA_ch_can_be_suspended.
 * @param {dma_ch_preempt_ability_te} dpa:DMA channel preempt ability enumeration,
 *                                    where can be DMA_ch_can_suspend,DMA_ch_cannot_suspend
 * @return {void}
 */
void DMA_Configuration_Channel_Preemption(dma_tcd *ch, dma_ch_preemption_te ecp, dma_ch_preempt_ability_te dpa)
{
    uint8_t tempReg = 0U;

    tempReg |= DMA_CPR_ECP(ecp) | DMA_CPR_DPA(dpa);

    ((uint8_t *)(&DMA->CPR3))[(ch - DMA_TCD_00) / 4U * 4U + 3U - (ch - DMA_TCD_00) % 4U] &= 0x3FU;
    ((uint8_t *)(&DMA->CPR3))[(ch - DMA_TCD_00) / 4U * 4U + 3U - (ch - DMA_TCD_00) % 4U] |= tempReg;
}

/**
 * @brief DMA Channel Start
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 *               structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Start(dma_tcd *ch)
{
    DMA->SSBR = ch - DMA_TCD_00;
}

/**
 * @brief DMA Clear Channel's done bit state
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 *               structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Clear_Done(dma_tcd *ch)
{
    DMA->CDSBR = ch - DMA_TCD_00;
}

/**
 * @brief Get DMA Channel Done bit state
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 *               structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {FlagStatus} Return value can be RESET,SET.
 */
FlagStatus DMA_Channel_Check_Donebit(dma_tcd *ch)
{
    return (ch->CONTROL_STATUS & DMA_TCD_CONTROL_STATUS_DONE_MARK) >> DMA_TCD_CONTROL_STATUS_DONE_SHIFT;
}

/**
 * @brief Get DMA Channel Active bit state
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 *               structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {FlagStatus} Return value can be RESET,SET.
 */
FlagStatus DMA_Channel_Check_Activebit(dma_tcd *ch)
{
    return (ch->CONTROL_STATUS & DMA_TCD_CONTROL_STATUS_ACTIVE_MARK) >> DMA_TCD_CONTROL_STATUS_ACTIVE_SHIFT;
}

/**
 * @brief DMA Clear Channel Major or Half Interrupt Flag
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 *               structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Clear_InterruptFlag(dma_tcd *ch)
{
    DMA->CIRQR = ch - DMA_TCD_00;
}
/**
 * @brief DMA Check Channel Major or Half Interrupt Request
 * @param {dma_tcd *} ch:Pointer to a DMA Channel Transfer Control Descriptor
 *              structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {FlagStatus} Return value can be RESET,SET.
 */
FlagStatus DMA_Channel_Check_Interrupt(dma_tcd *ch)
{
    return ((DMA->IRQRL & (1U << (ch - DMA_TCD_00))) >> (ch - DMA_TCD_00));
}

/**
 * @brief DMA Enable Channel Error Interrupt.
 * @param {dma_tcd *} ch:Pointer to a DMA Channel Transfer Control Descriptor
 *              structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Error_Interrupt_Enable(dma_tcd *ch)
{
    DMA->SEEIR = ch - DMA_TCD_00;
}
/**
 * @brief DMA Disable Channel Error Interrupt.
 * @param {dma_tcd *} ch:Pointer to a DMA Channel Transfer Control Descriptor
 *              structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Error_Interrupt_Disable(dma_tcd *ch)
{
    DMA->CEEIR = ch - DMA_TCD_00;
}
/**
 * @brief DMA Check Channel Error Interrupt Status
 * @param {dma_tcd *} ch:Pointer to a DMA Channel Transfer Control Descriptor
 *              structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {FlagStatus} Return value can be RESET,SET.
 */
FlagStatus DMA_Channel_Check_Error_Interrupt(dma_tcd *ch)
{
    return ((DMA->ERL & (1U << (ch - DMA_TCD_00))) >> (ch - DMA_TCD_00));
}

/**
 * @brief DMA Clear Channel Error Interrupt Flag
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 * structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Clear_Error_InterruptFlag(dma_tcd *ch)
{
    DMA->CER = ch - DMA_TCD_00;
}


/**
 * @brief Enable DMA Channel Hardware request
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 *               structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Hardware_Request_Enable(dma_tcd *ch)
{
    DMA->SERQR = ch - DMA_TCD_00;
}

/**
 * @brief Disable DMA Channel Hardware request
 * @param {dma_tcd *} ch: Pointer to a DMA Channel Transfer Control Descriptor
 *               structure, where can be DMA_TCD_00,DMA_TCD_01, ... DMA_TCD_15.
 * @return {void}
 */
void DMA_Channel_Hardware_Request_Disable(dma_tcd *ch)
{
    DMA->CERQR = ch - DMA_TCD_00;
}




